package com.example.venue_reservation_service.netty;

import com.example.venue_reservation_service.entity.ChatMessage;
import com.example.venue_reservation_service.repository.ChatMessageRepository;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

@Component
@Scope("prototype")
@ChannelHandler.Sharable
public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private static final Map<String, Channel> userChannelMap = new HashMap<>();
    private static final Map<Integer, String> roleMap = new HashMap<>();

    @Autowired
    private ChatMessageRepository chatMessageRepository;

    static {
        roleMap.put(0, "普通用户");
        roleMap.put(1, "普通用户");
        roleMap.put(2, "普通用户");
        roleMap.put(3, "系统管理员");
        roleMap.put(4, "超级管理员");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        channels.add(incoming);
        System.out.println("New client connected: " + incoming.remoteAddress());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        String username = null;

        for (Map.Entry<String, Channel> entry : userChannelMap.entrySet()) {
            if (entry.getValue().equals(incoming)) {
                username = entry.getKey();
                break;
            }
        }

        if (username != null) {
            userChannelMap.remove(username);
            broadcastMessage("系统通知", username + " 已退出聊天", 3);
        }

        channels.remove(incoming);
        System.out.println("Client disconnected: " + incoming.remoteAddress());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
        String request = frame.text();
        Channel incoming = ctx.channel();

        try {
            JSONObject jsonObject = JSON.parseObject(request);
            String type = jsonObject.getString("type");

            if ("login".equals(type)) {
                handleLogin(incoming, jsonObject);
            } else if ("message".equals(type)) {
                handleMessage(incoming, jsonObject);
            } else if ("loadHistory".equals(type)) {
                handleLoadHistory(incoming, jsonObject);
            } else {
                sendErrorMessage(incoming, "未知消息类型: " + type);
            }
        } catch (Exception e) {
            System.err.println("Error processing message: " + e.getMessage());
            e.printStackTrace();
            sendErrorMessage(incoming, "消息格式错误");
        }
    }

    private void handleLogin(Channel incoming, JSONObject jsonObject) {
        String username = jsonObject.getString("username");
        int userRole = jsonObject.getIntValue("userRole");

        if (username == null || username.isEmpty()) {
            sendErrorMessage(incoming, "用户名不能为空");
            return;
        }

        if (userChannelMap.containsKey(username)) {
            sendErrorMessage(incoming, "用户名已被使用");
            return;
        }

        userChannelMap.put(username, incoming);
        String roleName = roleMap.getOrDefault(userRole, "未知角色");
        broadcastMessage("系统通知", username + " (" + roleName + ") 加入了聊天", 3);
        System.out.println(username + " logged in with role: " + roleName);
    }

    private void handleMessage(Channel incoming, JSONObject jsonObject) {
        String username = jsonObject.getString("username");
        int userRole = jsonObject.getIntValue("userRole");
        String content = jsonObject.getString("content");

        if (content == null || content.isEmpty()) {
            return;
        }

        if (!userChannelMap.containsKey(username) || !userChannelMap.get(username).equals(incoming)) {
            sendErrorMessage(incoming, "用户未登录");
            return;
        }

        // 保存消息到MongoDB
        ChatMessage chatMessage = new ChatMessage(username, userRole, content);
        chatMessageRepository.save(chatMessage);

        String roleName = roleMap.getOrDefault(userRole, "未知角色");
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        JSONObject messageJson = new JSONObject();
        messageJson.put("type", "message");
        messageJson.put("sender", username);
        messageJson.put("senderRole", userRole);
        messageJson.put("roleName", roleName);
        messageJson.put("content", content);
        messageJson.put("timestamp", timestamp);

        broadcastMessage(messageJson.toJSONString());
    }

    private void handleLoadHistory(Channel incoming, JSONObject jsonObject) {
        String username = jsonObject.getString("username");
        long lastTimestamp = jsonObject.getLongValue("lastTimestamp");
        int pageSize = jsonObject.getIntValue("pageSize");

        if (!userChannelMap.containsKey(username) || !userChannelMap.get(username).equals(incoming)) {
            sendErrorMessage(incoming, "用户未登录");
            return;
        }

        LocalDateTime beforeDate = lastTimestamp == 0 ? LocalDateTime.now()
                : LocalDateTime.ofEpochSecond(lastTimestamp/1000, 0, java.time.ZoneOffset.UTC);

        Page<ChatMessage> messages = chatMessageRepository.findByTimestampBeforeOrderByTimestampDesc(
                beforeDate,
                org.springframework.data.domain.PageRequest.of(0, pageSize)
        );

        JSONObject response = new JSONObject();
        response.put("type", "history");
        response.put("messages", messages.getContent());
        response.put("hasMore", !messages.isLast());

        incoming.writeAndFlush(new TextWebSocketFrame(response.toJSONString()));
    }

    private void broadcastMessage(String message) {
        for (Channel channel : channels) {
            channel.writeAndFlush(new TextWebSocketFrame(message));
        }
    }

    private void broadcastMessage(String from, String content, int role) {
        JSONObject messageJson = new JSONObject();
        messageJson.put("type", "system");
        messageJson.put("sender", from);
        messageJson.put("senderRole", role);
        messageJson.put("message", content);
        messageJson.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        broadcastMessage(messageJson.toJSONString());
    }

    private void sendErrorMessage(Channel channel, String message) {
        JSONObject errorJson = new JSONObject();
        errorJson.put("type", "error");
        errorJson.put("message", message);
        channel.writeAndFlush(new TextWebSocketFrame(errorJson.toJSONString()));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Channel channel = ctx.channel();
        String username = null;

        for (Map.Entry<String, Channel> entry : userChannelMap.entrySet()) {
            if (entry.getValue().equals(channel)) {
                username = entry.getKey();
                break;
            }
        }

        if (username != null) {
            userChannelMap.remove(username);
            broadcastMessage("系统通知", username + " 连接异常断开", 3);
        }

        cause.printStackTrace();
        ctx.close();
    }
}